package code.generate;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.lang.StringUtils;

import code.generate.bean.Table;
import code.generate.singleton.ConfigSingleton;

import com.google.common.base.CaseFormat;
import com.google.common.collect.Maps;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * Created by vcd on 2014/3/25.
 */
public class Generate {

	private Configuration cfg;
	private Configuration cfgSingle;
	private File templates;
	private File templatesSingle;
	String ignoredpath = "templates_single/src/main/webapp/resources";

	private ConfigSingleton configSingleton = ConfigSingleton.getInstance();

	private static List<Table> tables = new ArrayList<Table>();

	public static String opSqlFile = null;

	public Generate() throws IOException {
		// 指定模板文件从何处加载的数据源，这里设置成一个文件目录。
		System.out.println(this.getClass().getResource("/").getPath() + "/templates");
		templates = new File(this.getClass().getResource("/").getPath() + "/templates");
		templatesSingle = new File(this.getClass().getResource("/").getPath() + "/templates_single");
		cfg = new Configuration();
		cfg.setObjectWrapper(new DefaultObjectWrapper());
		cfg.setDefaultEncoding("UTF-8");
		cfg.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
		cfgSingle = (Configuration) cfg.clone();
		cfg.setDirectoryForTemplateLoading(templates);
		cfgSingle.setDirectoryForTemplateLoading(templatesSingle);
	}

	public void generate(Table table) throws IOException, TemplateException {
		System.out.println(templates.getPath());
		String basePath = templates.getPath();
		Iterator<File> iterator = FileUtils.iterateFiles(templates, ExtensionFileFilter.INSTANCE,
				TrueFileFilter.INSTANCE);

		tables.add(table);

		Map<String, Object> model = buildModel();

		model.put("table", table);
		
		//如果是增量生成模式，判断是否为新加入的表
		if (isAddMode()) {
			if (!isAddTable(table.getDbName())) {
				System.out.println("Not additional table: " + table.getDbName());
				return;
			}
		}

		while (iterator.hasNext()) {
			File f = iterator.next();
			String templateName = f.getAbsolutePath().replace(basePath + File.separator, "");

			Template temp = cfg.getTemplate(templateName);
			String outpath = configSingleton.getProperties().getProperty("outpath", "/out");
			String outStr = outpath + "/" + TemplateProcessor.processTemplateString(templateName, model, cfg);
			FileUtils.forceMkdir(new File(outStr).getParentFile());
			Writer out = new FileWriter(outStr);

			temp.process(model, out);
			out.flush();
		}
	}

	public void generateSingle() throws IOException, TemplateException {
		System.out.println(templatesSingle.getPath());
		String basePath = templatesSingle.getPath();
		Iterator<File> iterator = FileUtils.iterateFiles(templatesSingle, FileFileFilter.FILE, TrueFileFilter.INSTANCE);
		Map<String, Object> model = buildModel();
		model.put("tables", tables);

		// 在忽略列表中的文件不会被解析，直接复制到目标目录
		File ignoreFile = new File(ignoredpath);
		String ignorePath = ignoreFile.getPath();

		while (iterator.hasNext()) {
			File f = iterator.next();
			String pth = f.getPath();
			if (pth.indexOf(ignorePath) == -1 && ExtensionFileFilter.INSTANCE.accept(f)) {
				String templateName = f.getAbsolutePath().replace(basePath + File.separator, "");
				Template temp = cfgSingle.getTemplate(templateName);
				String outpath = configSingleton.getProperties().getProperty("outpath", "/out");
				String outStr = outpath + "/" + TemplateProcessor.processTemplateString(templateName, model, cfgSingle);
				FileUtils.forceMkdir(new File(outStr).getParentFile());
				Writer out = new FileWriter(outStr);
				temp.process(model, out);
				out.flush();
				String fileType = f.getName().replaceAll("^.+\\.", "");
				if (fileType.equals("sql")) {
					opSqlFile = outStr;
				}
			} else {
				String templateName = f.getAbsolutePath().replace(basePath + File.separator, "");
				String outpath = configSingleton.getProperties().getProperty("outpath", "/out");
				String outStr = outpath + "/" + TemplateProcessor.processTemplateString(templateName, model, cfgSingle);
				File desFile = new File(outStr);
				FileUtils.forceMkdir(desFile.getParentFile());
				FileUtils.copyFile(f, desFile);
			}
		}
	}
	
	public void generateAddSingle() throws IOException, TemplateException {
		System.out.println(templatesSingle.getPath());
		String basePath = templatesSingle.getPath();
		Map<String, Object> model = buildModel();
		model.put("tables", tables);

		// 只解析5个需要覆盖的文件
		String[] updatePaths = {
				basePath + "/src/main/resources/sqlmap-${databaseNameCamel}.xml",
				basePath + "/i18nText/applicationResources_zh.txt",
				basePath + "/src/main/resources/applicationResources_zh.properties",
				basePath + "/src/main/resources/ExcaliburShiro.properties",
				basePath + "/src/main/webapp/WEB-INF/sitemesh/default.jsp"};

		for (int i=0; i<updatePaths.length; i++) {
			File f = new File(updatePaths[i]);
			if (ExtensionFileFilter.INSTANCE.accept(f)) {
				String templateName = f.getAbsolutePath().replace(basePath + File.separator, "");
				Template temp = cfgSingle.getTemplate(templateName);
				String outpath = configSingleton.getProperties().getProperty("outpath", "/out");
				String outStr = outpath + "/" + TemplateProcessor.processTemplateString(templateName, model, cfgSingle);
				FileUtils.forceMkdir(new File(outStr).getParentFile());
				Writer out = new FileWriter(outStr);
				temp.process(model, out);
				out.flush();
				String fileType = f.getName().replaceAll("^.+\\.", "");
				if (fileType.equals("sql")) {
					opSqlFile = outStr;
				}
			} else {
				String templateName = f.getAbsolutePath().replace(basePath + File.separator, "");
				String outpath = configSingleton.getProperties().getProperty("outpath", "/out");
				String outStr = outpath + "/" + TemplateProcessor.processTemplateString(templateName, model, cfgSingle);
				File desFile = new File(outStr);
				FileUtils.forceMkdir(desFile.getParentFile());
				FileUtils.copyFile(f, desFile);
			}
		}
	}

	public Map<String, Object> buildModel() {
		Map<String, Object> model = new HashMap<String, Object>();
		model.putAll(Maps.fromProperties(configSingleton.getProperties()));
		String basepackage = configSingleton.getProperties().getProperty("basepackage", "com.test");
		String databaseName = configSingleton.getProperties().getProperty("databaseName", "common");
		String doman = configSingleton.getProperties().getProperty("doman", "demo.onekeyop.com");
		model.put("crossDoman", doman.replaceAll("^.*?\\.", "\\*\\."));
		model.put("basepackage_dir", basepackage.replace(".", "/"));
		model.put("databaseNameCamel", CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, databaseName));
		model.put("capDatabaseNameCamel",
				StringUtils.capitalize(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, databaseName)));
		return model;
	}

	public boolean isExcludeTable(String tableDbName) {
		if (StringUtils.isNotBlank(tableDbName)) {
			String excludeTablesStr = configSingleton.getProperties().getProperty("excludeTables", "");
			String[] excludeTables = excludeTablesStr.split(",");
			if (excludeTables != null && excludeTables.length > 0) {
				for (String excludeTable : excludeTables) {
					if (tableDbName.equalsIgnoreCase(excludeTable)) {
						return true;
					}
				}
			}
			return false;
		}
		return true;
	}

	public boolean isIncludeTable(String tableDbName) {
		if (StringUtils.isNotBlank(tableDbName)) {
			String includeTablesStr = configSingleton.getProperties().getProperty("includeTables", "");
			String[] includeTables = includeTablesStr.split(",");
			if (includeTables != null && includeTables.length > 0) {
				for (String includeTable : includeTables) {
					if (tableDbName.equalsIgnoreCase(includeTable)) {
						return true;
					}
				}
				return false;
			}
		}
		return true;
	}

	public boolean isAddTable(String tableDbName) {
		if (StringUtils.isNotBlank(tableDbName)) {
			String addTablesStr = configSingleton.getProperties().getProperty("addTables", "");
			String[] addTables = addTablesStr.split(",");
			if (addTables != null && addTables.length > 0) {
				for (String addTable : addTables) {
					if (tableDbName.equalsIgnoreCase(addTable)) {
						return true;
					}
				}
				return false;
			}
		}
		return true;
	}
	
	public boolean needCreateOpDb(){
		String createopdb = configSingleton.getProperties().getProperty("createopdb", "no");
		return createopdb.equals("yes")?true:false;
	}
	
	public boolean isAddMode(){
		String createopdb = configSingleton.getProperties().getProperty("isAddMode", "no");
		return createopdb.equals("yes")?true:false;
	}

	public boolean hasIncludeConfig() {
		String includeTablesStr = configSingleton.getProperties().getProperty("includeTables", "");
		return StringUtils.isNotBlank(includeTablesStr);
	}

}
